home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ue312src.zip / BUFFER.C < prev    next >
C/C++ Source or Header  |  1993-03-26  |  15KB  |  602 lines

  1. /*  BUFFER.C:    buffer mgmt. routines
  2.         MicroEMACS 3.12
  3.  
  4.  * Buffer management.
  5.  * Some of the functions are internal,
  6.  * and some are actually attached to user
  7.  * keys. Like everyone else, they set hints
  8.  * for the display system.
  9.  */
  10. #include    <stdio.h>
  11. #include    "estruct.h"
  12. #include    "eproto.h"
  13. #include    "edef.h"
  14. #include    "elang.h"
  15.  
  16. /*
  17.  * Attach a buffer to a window. The
  18.  * values of dot and mark come from the buffer
  19.  * if the use count is 0. Otherwise, they come
  20.  * from some other window.
  21.  */
  22. PASCAL NEAR usebuffer(f, n)
  23.  
  24. int f,n;    /* prefix flag and argument */
  25.  
  26. {
  27.     register BUFFER *bp;    /* temporary buffer pointer */
  28.  
  29.     /* get the buffer name to switch to */
  30.     bp = getdefb();
  31.     bp = getcbuf(TEXT24, bp ? bp->b_bname : mainbuf, TRUE);
  32. /*                "Use buffer" */
  33.     if (!bp)
  34.         return(ABORT);
  35.  
  36.     /* make it invisible if there is an argument */
  37.     if (f == TRUE)
  38.         bp->b_flag |= BFINVS;
  39.  
  40.     /* switch to it in any case */
  41.     return(swbuffer(bp));
  42. }
  43.  
  44. PASCAL NEAR nextbuffer(f, n)    /* switch to the next buffer in the buffer list */
  45.  
  46. int f, n;    /* default flag, numeric argument */
  47. {
  48.     register BUFFER *bp;    /* current eligable buffer */
  49.     register int status;
  50.  
  51.     /* make sure the arg is legit */
  52.     if (f == FALSE)
  53.         n = 1;
  54.     if (n < 1)
  55.         return(FALSE);
  56.  
  57.     /* cycle thru buffers until n runs out */
  58.     while (n-- > 0) {
  59.         bp = getdefb();
  60.         if (bp == NULL)
  61.             return(FALSE);
  62.         status = swbuffer(bp);
  63.         if (status != TRUE)
  64.             return(status);
  65.     }
  66.     return(status);
  67. }
  68.  
  69. PASCAL NEAR swbuffer(bp)    /* make buffer BP current */
  70.  
  71. BUFFER *bp;
  72.  
  73. {
  74.     register WINDOW *wp;
  75.     SCREEN *scrp;        /* screen to fix pointers in */
  76.     register int cmark;        /* current mark */
  77.  
  78.     /* let a user macro get hold of things...if he wants */
  79.     execkey(&exbhook, FALSE, 1);
  80.  
  81.     if (--curbp->b_nwnd == 0) {        /* Last use.        */
  82.         curbp->b_dotp  = curwp->w_dotp;
  83.         curbp->b_doto  = curwp->w_doto;
  84.         for (cmark = 0; cmark < NMARKS; cmark++) {
  85.             curbp->b_markp[cmark] = curwp->w_markp[cmark];
  86.             curbp->b_marko[cmark] = curwp->w_marko[cmark];
  87.         }
  88.         curbp->b_fcol  = curwp->w_fcol;
  89.     }
  90.     curbp = bp;                /* Switch.        */
  91.     if (curbp->b_active != TRUE) {        /* buffer not active yet*/
  92.         /* read it in and activate it */
  93.         readin(curbp->b_fname, ((curbp->b_mode&MDVIEW) == 0));
  94.         curbp->b_dotp = lforw(curbp->b_linep);
  95.         curbp->b_doto = 0;
  96.         curbp->b_active = TRUE;
  97.     }
  98.     curwp->w_bufp  = bp;
  99.     curwp->w_linep = bp->b_linep;        /* For macros, ignored. */
  100.     curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty.     */
  101.     if (bp->b_nwnd++ == 0) {        /* First use.        */
  102.         curwp->w_dotp  = bp->b_dotp;
  103.         curwp->w_doto  = bp->b_doto;
  104.         for (cmark = 0; cmark < NMARKS; cmark++) {
  105.             curwp->w_markp[cmark] = bp->b_markp[cmark];
  106.             curwp->w_marko[cmark] = bp->b_marko[cmark];
  107.         }
  108.         curwp->w_fcol  = bp->b_fcol;
  109.     } else {
  110.         /* in all screens.... */
  111.         scrp = first_screen;
  112.         while (scrp) {
  113.             wp = scrp->s_first_window;
  114.             while (wp != NULL) {
  115.                 if (wp!=curwp && wp->w_bufp==bp) {
  116.                     curwp->w_dotp  = wp->w_dotp;
  117.                     curwp->w_doto  = wp->w_doto;
  118.                     for (cmark = 0; cmark < NMARKS; cmark++) {
  119.                         curwp->w_markp[cmark] = wp->w_markp[cmark];
  120.                         curwp->w_marko[cmark] = wp->w_marko[cmark];
  121.                     }
  122.                     curwp->w_fcol  = wp->w_fcol;
  123.                     break;
  124.                 }
  125.                 /* next window */
  126.                 wp = wp->w_wndp;
  127.             }
  128.  
  129.             /* next screen! */
  130.             scrp = scrp->s_next_screen;
  131.         }
  132.     }
  133.  
  134.     /* let a user macro get hold of things...if he wants */
  135.     execkey(&bufhook, FALSE, 1);
  136.  
  137.     return(TRUE);
  138. }
  139.  
  140. /*
  141.  * Dispose of a buffer, by name.
  142.  * Ask for the name. Look it up (don't get too
  143.  * upset if it isn't there at all!). Get quite upset
  144.  * if the buffer is being displayed. Clear the buffer (ask
  145.  * if the buffer has been changed). Then free the header
  146.  * line and the buffer header. Bound to "C-X K".
  147.  */
  148. PASCAL NEAR killbuffer(f, n)
  149.  
  150. int f,n;    /* prefix flag and argument */
  151.  
  152. {
  153.     register BUFFER *bp;    /* ptr to buffer to dump */
  154.  
  155.     /* get the buffer name to kill */
  156.     bp = getdefb();
  157.     bp = getcbuf(TEXT26, bp ? bp->b_bname : mainbuf, TRUE);
  158. /*             "Kill buffer" */
  159.     if (bp == NULL)
  160.         return(ABORT);
  161.  
  162.     return(zotbuf(bp));
  163. }
  164.  
  165. /*    Allow the user to pop up a buffer, like we do.... */
  166.  
  167. PASCAL NEAR popbuffer(f, n)
  168.  
  169. int f, n;    /* default and numeric arguments */
  170.  
  171. {
  172.     register BUFFER *bp;    /* ptr to buffer to dump */
  173.  
  174.     /* get the buffer name to pop */
  175.     bp = getdefb();
  176.     bp = getcbuf(TEXT27, bp ? bp->b_bname : mainbuf, TRUE);
  177. /*             "Pop buffer" */
  178.     if (bp == NULL)
  179.         return(ABORT);
  180.  
  181.     /* make it invisible if there is an argument */
  182.     if (f == TRUE)
  183.         bp->b_flag |= BFINVS;
  184.  
  185.     return(pop(bp));
  186. }
  187.  
  188. BUFFER *PASCAL NEAR getdefb()    /* get the default buffer for a use or kill */
  189.  
  190. {
  191.     BUFFER *bp;    /* default buffer */
  192.  
  193.     /* Find the next buffer, which will be the default */
  194.     bp = curbp->b_bufp;
  195.  
  196.     /* cycle through the buffers to find an eligable one */
  197.     while (bp == NULL || bp->b_flag & BFINVS) {
  198.         if (bp == NULL)
  199.             bp = bheadp;
  200.         else
  201.             bp = bp->b_bufp;
  202.  
  203.         /* don't get caught in an infinite loop! */
  204.         if (bp == curbp) {
  205.             bp = NULL;
  206.             break;
  207.         }
  208.     }            
  209.     return(bp);
  210. }
  211.  
  212. PASCAL NEAR zotbuf(bp)    /* kill the buffer pointed to by bp */
  213.  
  214. register BUFFER *bp;
  215.  
  216. {
  217.     register BUFFER *bp1;
  218.     register BUFFER *bp2;
  219.     register int    s;
  220.  
  221.     /* we can not kill a displayed buffer */
  222.     if (bp->b_nwnd != 0) {
  223.         mlwrite(TEXT28);
  224. /*            "Buffer is being displayed" */
  225.         return(FALSE);
  226.     }
  227.  
  228.     /* we can not kill an executing buffer */
  229.     if (bp->b_exec != 0) {
  230.         mlwrite(TEXT226);
  231. /*            "%%Can not delete an executing buffer" */
  232.         return(FALSE);
  233.     }
  234.  
  235.     if ((s=bclear(bp)) != TRUE)        /* Blow text away.    */
  236.         return(s);
  237.     free((char *) bp->b_linep);        /* Release header line. */
  238.     bp1 = NULL;                /* Find the header.    */
  239.     bp2 = bheadp;
  240.     while (bp2 != bp) {
  241.         bp1 = bp2;
  242.         bp2 = bp2->b_bufp;
  243.     }
  244.     bp2 = bp2->b_bufp;            /* Next one in chain.    */
  245.     if (bp1 == NULL)            /* Unlink it.        */
  246.         bheadp = bp2;
  247.     else
  248.         bp1->b_bufp = bp2;
  249.     free((char *) bp);            /* Release buffer block */
  250.     return(TRUE);
  251. }
  252.  
  253. PASCAL NEAR namebuffer(f,n)    /*    Rename the current buffer    */
  254.  
  255. int f, n;        /* default Flag & Numeric arg */
  256.  
  257. {
  258.     register BUFFER *bp;    /* pointer to scan through all buffers */
  259.     char bufn[NBUFN];    /* buffer to hold buffer name */
  260.  
  261.     /* prompt for and get the new buffer name */
  262. ask:    if (mlreply(TEXT29, bufn, NBUFN) != TRUE)
  263. /*            "Change buffer name to: " */
  264.         return(FALSE);
  265.  
  266.     /* and check for duplicates */
  267.     bp = bheadp;
  268.     while (bp != NULL) {
  269.         if (bp != curbp) {
  270.             /* if the names the same */
  271.             if (strcmp(bufn, bp->b_bname) == 0)
  272.                 goto ask;  /* try again */
  273.         }
  274.         bp = bp->b_bufp;    /* onward */
  275.     }
  276.  
  277.     strcpy(curbp->b_bname, bufn);    /* copy buffer name to structure */
  278.     upmode();            /* make all mode lines replot */
  279.     mlerase();
  280.     return(TRUE);
  281. }
  282.  
  283. /*    Build and popup a buffer containing the list of all buffers.
  284.     Bound to "C-X C-B". A numeric argument forces it to list
  285.     invisible buffers as well.
  286. */
  287.  
  288. PASCAL NEAR listbuffers(f, n)
  289.  
  290. int f,n;    /* prefix flag and argument */
  291.  
  292. {
  293.     register int status;    /* stutus return */
  294.  
  295.     if ((status = makelist(f)) != TRUE)
  296.         return(status);
  297.     return(wpopup(blistp));
  298. }
  299.  
  300. /*
  301.  * This routine rebuilds the
  302.  * text in the special secret buffer
  303.  * that holds the buffer list. It is called
  304.  * by the list buffers command. Return TRUE
  305.  * if everything works. Return FALSE if there
  306.  * is an error (if there is no memory). Iflag
  307.  * indecates weather to list hidden buffers.
  308.  */
  309. PASCAL NEAR makelist(iflag)
  310.  
  311. int iflag;    /* list hidden buffer flag */
  312.  
  313. {
  314.     register char    *cp1;
  315.     register char    *cp2;
  316.     register int    c;
  317.     register BUFFER *bp;
  318.     register LINE    *lp;
  319.     register int    s;
  320.     register int    i;
  321.     long nbytes;        /* # of bytes in current buffer */
  322.     char b[7+1];
  323.     char line[128];
  324.  
  325.     blistp->b_flag &= ~BFCHG;        /* Don't complain!    */
  326.     if ((s=bclear(blistp)) != TRUE)     /* Blow old text away    */
  327.         return(s);
  328.     strcpy(blistp->b_fname, "");
  329.     if (addline(blistp, TEXT30) == FALSE
  330. /*            "ACTN   Modes       Size Buffer       File" */
  331.     ||  addline(blistp, "---- ---------  ------- --------------- ----") == FALSE)
  332.         return(FALSE);
  333.     bp = bheadp;                /* For all buffers    */
  334.  
  335.     /* build line to report global mode settings */
  336.     cp1 = &line[0];
  337.     *cp1++ = ' ';
  338.     *cp1++ = ' ';
  339.     *cp1++ = ' ';
  340.     *cp1++ = ' ';
  341.     *cp1++ = ' ';
  342.  
  343.     /* output the mode codes */
  344.     for (i = 0; i < NUMMODES; i++)
  345.         if (gmode & (1 << i))
  346.             *cp1++ = modecode[i];
  347.         else
  348.             *cp1++ = '.';
  349.     strcpy(cp1, TEXT31);
  350. /*            "          Global Modes" */
  351.     if (addline(blistp, line) == FALSE)
  352.         return(FALSE);
  353.  
  354.     /* output the list of buffers */
  355.     while (bp != NULL) {
  356.         /* skip invisible buffers if iflag is false */
  357.         if (((bp->b_flag&BFINVS) != 0) && (iflag != TRUE)) {
  358.             bp = bp->b_bufp;
  359.             continue;
  360.         }
  361.         cp1 = &line[0];         /* Start at left edge    */
  362.  
  363.         /* output status of ACTIVE flag (has the file been read in? */
  364.         if (bp->b_active == TRUE)    /* "@" if activated       */
  365.             *cp1++ = '@';
  366.         else
  367.             *cp1++ = ' ';
  368.  
  369.         /* output status of changed flag */
  370.         if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed    */
  371.             *cp1++ = '*';
  372.         else
  373.             *cp1++ = ' ';
  374.  
  375.         /* report if the file is truncated */
  376.         if ((bp->b_flag&BFTRUNC) != 0)
  377.             *cp1++ = '#';
  378.         else
  379.             *cp1++ = ' ';
  380.  
  381.         /* report if the file is narrowed */
  382.         if ((bp->b_flag&BFNAROW) != 0)
  383.             *cp1++ = '<';
  384.         else
  385.             *cp1++ = ' ';
  386.  
  387.         *cp1++ = ' ';    /* space */
  388.  
  389.         /* output the mode codes */
  390.         for (i = 0; i < NUMMODES; i++) {
  391.             if (bp->b_mode & (1 << i))
  392.                 *cp1++ = modecode[i];
  393.             else
  394.                 *cp1++ = '.';
  395.         }
  396.         *cp1++ = ' ';            /* Gap.         */
  397.         nbytes = 0L;            /* Count bytes in buf.    */
  398.         lp = lforw(bp->b_linep);
  399.         while (lp != bp->b_linep) {
  400.             nbytes += (long)lused(lp)+1L;
  401.             lp = lforw(lp);
  402.         }
  403.         flong_asc(b, 7, nbytes);         /* 6 digit buffer size. */
  404.         cp2 = &b[0];
  405.         while (*cp2)
  406.             *cp1++ = *cp2++;
  407.         *cp1++ = ' ';            /* Gap.         */
  408.         cp2 = &bp->b_bname[0];        /* Buffer name        */
  409.         while (*cp2)
  410.             *cp1++ = *cp2++;
  411.         *cp1++ = ' ';            /* Gap.         */
  412.         cp2 = &bp->b_fname[0];        /* File name        */
  413.         if (*cp2 != 0) {
  414.             while (cp1 < &line[40])
  415.                 *cp1++ = ' ';
  416.             while (*cp2)
  417.                 *cp1++ = *cp2++;
  418.         }
  419.         *cp1 = 0;          /* Add to the buffer.   */
  420.         if (addline(blistp, line) == FALSE)
  421.             return(FALSE);
  422.         bp = bp->b_bufp;
  423.     }
  424.     return(TRUE);                   /* All done           */
  425. }
  426.  
  427. /* Translate a long to ascii form. Don't trust various systems
  428.    ltoa() routines.. they aren't consistant                */
  429.  
  430. VOID PASCAL NEAR flong_asc(buf, width, num)
  431.  
  432. char   buf[];
  433. int    width;
  434. long   num;
  435.  
  436. {
  437.     buf[width] = 0;             /* End of string.    */
  438.     while (num >= 10) {            /* Conditional digits.    */
  439.         buf[--width] = (int)(num%10L) + '0';
  440.         num /= 10L;
  441.     }
  442.     buf[--width] = (int)num + '0';        /* Always 1 digit.    */
  443.     while (width != 0)            /* Pad with blanks.    */
  444.         buf[--width] = ' ';
  445. }
  446.  
  447. /*
  448.  * Look through the list of
  449.  * buffers. Return TRUE if there
  450.  * are any changed buffers. Buffers
  451.  * that hold magic internal stuff are
  452.  * not considered; who cares if the
  453.  * list of buffer names is hacked.
  454.  * Return FALSE if no buffers
  455.  * have been changed.
  456.  */
  457. PASCAL NEAR anycb()
  458. {
  459.     register BUFFER *bp;
  460.  
  461.     bp = bheadp;
  462.     while (bp != NULL) {
  463.         if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
  464.             return(TRUE);
  465.         bp = bp->b_bufp;
  466.     }
  467.     return(FALSE);
  468. }
  469.  
  470. /*
  471.  * Find a buffer, by name. Return a pointer
  472.  * to the BUFFER structure associated with it.
  473.  * If the buffer is not found
  474.  * and the "cflag" is TRUE, create it. The "bflag" is
  475.  * the settings for the flags in in buffer.
  476.  */
  477. BUFFER *PASCAL NEAR bfind(bname, cflag, bflag)
  478.  
  479. register char    *bname; /* name of buffer to find */
  480. int cflag;        /* create it if not found? */
  481. int bflag;        /* bit settings for a new buffer */
  482.  
  483. {
  484.     register BUFFER *bp;
  485.     register BUFFER *sb;    /* buffer to insert after */
  486.     register LINE    *lp;
  487.     int cmark;        /* current mark */
  488.  
  489.     bp = bheadp;
  490.     while (bp != NULL) {
  491.         if (strcmp(bname, bp->b_bname) == 0)
  492.             return(bp);
  493.         bp = bp->b_bufp;
  494.     }
  495.  
  496.     /* no such buffer exists, create it? */
  497.     if (cflag != FALSE) {
  498.  
  499.         /* allocate the needed memory */
  500.         if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
  501.             return(NULL);
  502.         if ((lp=lalloc(0)) == NULL) {
  503.             free((char *) bp);
  504.             return(NULL);
  505.         }
  506.  
  507.         /* find the place in the list to insert this buffer */
  508.         if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
  509.             /* insert at the beginning */
  510.             bp->b_bufp = bheadp;
  511.             bheadp = bp;
  512.         } else {
  513.             sb = bheadp;
  514.             while (sb->b_bufp != NULL) {
  515.                 if (strcmp(sb->b_bufp->b_bname, bname) > 0)
  516.                     break;
  517.                 sb = sb->b_bufp;
  518.             }
  519.  
  520.             /* and insert it */
  521.             bp->b_bufp = sb->b_bufp;
  522.             sb->b_bufp = bp;
  523.         }
  524.  
  525.         /* and set up the other buffer fields */
  526.         bp->b_topline = NULL;
  527.         bp->b_botline = NULL;
  528.         bp->b_active = TRUE;
  529.         bp->b_dotp  = lp;
  530.         bp->b_doto  = 0;
  531.         for (cmark = 0; cmark < NMARKS; cmark++) {
  532.             bp->b_markp[cmark] = NULL;
  533.             bp->b_marko[cmark] = 0;
  534.         }
  535.         bp->b_fcol  = 0;
  536.         bp->b_flag  = bflag;
  537.         bp->b_mode  = gmode;
  538.         bp->b_nwnd  = 0;
  539.         bp->b_exec  = 0;
  540.         bp->b_linep = lp;
  541.         strcpy(bp->b_fname, "");
  542.         strcpy(bp->b_bname, bname);
  543. #if    CRYPT
  544.         bp->b_key[0] = 0;
  545. #endif
  546.         lp->l_fp = lp;
  547.         lp->l_bp = lp;
  548.     }
  549.     return(bp);
  550. }
  551.  
  552. /*
  553.  * This routine blows away all of the text
  554.  * in a buffer. If the buffer is marked as changed
  555.  * then we ask if it is ok to blow it away; this is
  556.  * to save the user the grief of losing text. The
  557.  * window chain is nearly always wrong if this gets
  558.  * called; the caller must arrange for the updates
  559.  * that are required. Return TRUE if everything
  560.  * looks good.
  561.  */
  562. PASCAL NEAR bclear(bp)
  563. register BUFFER *bp;
  564. {
  565.     register LINE    *lp;
  566.     register int    s;
  567.     int cmark;        /* current mark */
  568.  
  569.     if ((bp->b_flag&BFINVS) == 0        /* Not scratch buffer.    */
  570.     && (bp->b_flag&BFCHG) != 0        /* Something changed    */
  571.     && (s=mlyesno(TEXT32)) != TRUE)
  572. /*              "Discard changes" */
  573.         return(s);
  574.     bp->b_flag  &= ~BFCHG;            /* Not changed        */
  575.     while ((lp=lforw(bp->b_linep)) != bp->b_linep)
  576.         lfree(lp);
  577.     bp->b_dotp  = bp->b_linep;        /* Fix "."        */
  578.     bp->b_doto  = 0;
  579.     for (cmark = 0; cmark < NMARKS; cmark++) {
  580.         bp->b_markp[cmark] = NULL;  /* Invalidate "mark"    */
  581.         bp->b_marko[cmark] = 0;
  582.     }
  583.     bp->b_fcol = 0;
  584.     return(TRUE);
  585. }
  586.  
  587. PASCAL NEAR unmark(f, n)    /* unmark the current buffers change flag */
  588.  
  589. int f, n;    /* unused command arguments */
  590.  
  591. {
  592.     register WINDOW *wp;
  593.  
  594.     /* unmark the buffer */
  595.     curbp->b_flag &= ~BFCHG;
  596.  
  597.     /* unmark all windows as well */
  598.     upmode();
  599.  
  600.     return(TRUE);
  601. }
  602.